package com.xiongtian.springframework.aop.framework;

import com.xiongtian.springframework.aop.AdvisedSupport;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


import java.lang.reflect.Method;

/**
 * @Author: xiongtian
 * @CreateTime: 2025-04-17  17:54
 * @Version: 1.0
 * @Description: Cglib 代理工厂
 * <p>
 * 1. 实现 AopProxy 接口，用于获取代理类
 * 2. 实现 MethodInterceptor 接口，用于拦截目标方法
 */

public class Cglib2AopProxy implements AopProxy {

    private final AdvisedSupport advised;

    public  Cglib2AopProxy(AdvisedSupport advised) {
        this.advised = advised;
    }


    /**
     * 获取代理类
     *
     * @return 代理类
     */
    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
        enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
        enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
        return enhancer.create();
    }

    /**
     * 动态代理拦截器
     * 实现 MethodInterceptor 接口，用于拦截目标方法
     */
    private static class DynamicAdvisedInterceptor implements MethodInterceptor {
        private final AdvisedSupport advised;

        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }

        /**
         * 拦截目标方法
         * 1. 检查目标方法是否符合通知条件
         * 2. 调用 MethodInterceptor 的 invoke 方法
         * 3. 调用 MethodInvocation 的 proceed 方法
         * 4. 调用目标方法
         * 5. 返回目标方法的返回值
         * 6. 抛出异常
         *
         * @param o           代理对象
         * @param method      目标方法
         * @param objects     目标方法的参数
         * @param methodProxy 目标方法的代理对象
         * @return 目标方法的返回值
         * @throws Throwable 抛出异常
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
            if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
                return advised.getMethodInterceptor().invoke(methodInvocation);
            }
            return methodInvocation.proceed();
        }
    }

    /**
     * Cglib 方法调用
     * 实现 MethodInvocation 接口，用于调用目标方法
     * 1. 实现 MethodInvocation 接口，用于调用目标方法
     * 2. 实现 proceed 方法，用于调用目标方法
     * 3. 实现 getMethod 方法，用于获取目标方法
     * 4. 实现 getArguments 方法，用于获取目标方法的参数
     */
    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        private final MethodProxy methodProxy;

        public CglibMethodInvocation(Object target, Method method, Object[] arguments, MethodProxy methodProxy) {
            super(target, method, arguments);
            this.methodProxy = methodProxy;
        }

        /**
         * 调用目标方法
         *
         * @return 目标方法的返回值
         * @throws Throwable 抛出异常
         */
        @Override
        public Object proceed() throws Throwable {
            return this.methodProxy.invoke(this.target, this.arguments);
        }
    }
}
